#include "parser.h"
#include <cassert>

// prog : (expr? ";")*
// expr : term (("+" | "-") term)* ;
// term : factor (("*" | "/") factor)* ;
// factor : number | "(" expr ")" ;
// number: ([0-9])+ ;

std::shared_ptr<Program> Parser::ParseProgram()
{
    std::vector<std::shared_ptr<Expr>> ExprVec;
    while(token.tokenType != TokenType::eof)
    {
        // 遇到 ; 需要进行消费 token
        if(token.tokenType == TokenType::semi)
        {
            Advance();
            continue;
        }
        auto expr = ParseExpr();
        ExprVec.push_back(expr);
    }
    auto program = std::make_shared<Program>();
    program->ExprVec = std::move(ExprVec);
    return program;
}

std::shared_ptr<Expr> Parser::ParseExpr()
{
    std::shared_ptr<Expr> left = ParseTerm();

    while(token.tokenType == TokenType::plus || token.tokenType == TokenType::minus)
    {
        OpCode op;
        if(token.tokenType == TokenType::plus)
        {
            op = OpCode::add;
        }
        else
        {
            op = OpCode::sub;
        }
        Advance();
        auto binaryExpr = std::make_shared<BinaryExpr>();
        binaryExpr->left = left;
        binaryExpr->op = op;
        binaryExpr->right = ParseTerm();
        
        left = binaryExpr;
    }   
    return left; 
}

std::shared_ptr<Expr> Parser::ParseTerm()
{
    std::shared_ptr<Expr> left = ParseFactor();

    while(token.tokenType == TokenType::star || token.tokenType == TokenType::slash)
    {
        OpCode op;
        if(token.tokenType == TokenType::star)
        {
            op = OpCode::mul;
        }
        else
        {
            op = OpCode::div;
        }
        Advance();
        auto binaryExpr = std::make_shared<BinaryExpr>();
        binaryExpr->left = left;
        binaryExpr->op = op;
        binaryExpr->right = ParseFactor();
        
        left = binaryExpr;
    }    
    return left;
}

std::shared_ptr<Expr> Parser::ParseFactor()
{
    if(token.tokenType == TokenType::l_parent)
    {
        Advance();
        auto expr = ParseExpr();
        assert(Expect(TokenType::r_parent));
        Advance();
        return expr;
    }
    else
    {
        auto factorExpr = std::make_shared<FactorExpr>();
        factorExpr->number = token.value;
        Advance();
        return factorExpr;
    }
}

bool Parser::Expect(TokenType tokenType)
{
    return token.tokenType == tokenType;
}

bool Parser::Consume(TokenType tokenType)
{
    if(Expect(tokenType))
    {
        Advance();
        return true;
    }
    return false;
}

bool Parser::Advance()
{
    lexer.NextToken(token);
    return true;
}